﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using WpfApp1.Models;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using System.Reflection;

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace WpfApp1.Services
{
    class WPFUtils
    {

    }

    public class TreeHelper
    {
        /// <summary>
        /// 创建树
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="root">根节点</param>
        /// <param name="list">所有数据</param>
        /// <param name="idProperty">节点唯一标识属性表达式</param>
        /// <param name="parentIdProperty">父节点属性表达式</param>
        public static void CreateTree<T>(T root, IList<T> list, string idPropertyName, string parentIdPropertyName) where T : TreeBase<T>
        {
            root.Children = new ObservableCollection<T>();
            list.Where(e => (string)GetPropertyValue(e, parentIdPropertyName) == (string)GetPropertyValue(root, idPropertyName) && !e.IsLinked).ToList().ForEach(e => { root.Children.Add(e); e.IsLinked = true; });
            foreach (var leaf in root.Children)
            {
                leaf.Parent = root;
                CreateTree<T>(leaf, list, idPropertyName, parentIdPropertyName);
            }
        }

        /// <summary>
        /// 创建多个根节点的树
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="root">根节点</param>
        /// <param name="list">所有数据</param>
        /// <param name="idProperty">节点唯一标识属性表达式</param>
        /// <param name="parentIdProperty">父节点属性表达式</param>
        public static ObservableCollection<T> CreateTree<T>(IList<T> list, Expression<Func<T, object>> idProperty, Expression<Func<T, object>> parentIdProperty) where T : TreeBase<T>
        {
            //查找父节点不存在的leaf,作伪根节点
            var roots = new ObservableCollection<T>();
            var idPropertyName = GetMemberName(idProperty);
            var parentIdPropertyName = GetMemberName(parentIdProperty);
            list.Where(e => list.Count(item =>
                    (string)GetPropertyValue(item, idPropertyName) == (string)GetPropertyValue(e, parentIdPropertyName)) == 0).ToList().ForEach(e => roots.Add(e));
            foreach (var root in roots)
            {
                CreateTree<T>(root, list, idPropertyName, parentIdPropertyName);
            }
            return roots;
        }

        private static object GetPropertyValue<T>(T t, string propertyName)
        {
            return t.GetType().GetProperty(propertyName).GetValue(t, null);
        }

        private static string GetMemberName<T, TMember>(Expression<Func<T, TMember>> propertySelector)
        {
            var propertyExp = propertySelector.Body as MemberExpression;
            if (propertyExp == null)
            {
                throw new ArgumentException("不合理的表达式!");
            }
            return propertyExp.Member.Name;
        }

        /// <summary>
        /// 利用反射机制进行深拷贝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopyByReflect<T>(T obj)
        {
            //如果是字符串或值类型则直接返回
            if (obj is string || obj.GetType().IsValueType) return obj;

            object retval = Activator.CreateInstance(obj.GetType());
            FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
            foreach (FieldInfo field in fields)
            {
                try { field.SetValue(retval, DeepCopyByReflect(field.GetValue(obj))); }
                catch { }
            }
            return (T)retval;
        }

        /// <summary>
        /// 利用BIM文件进行深拷贝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopyByBin<T>(T obj)
        {
            object retval;
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                //序列化成流
                bf.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                //反序列化成对象
                retval = bf.Deserialize(ms);
                ms.Close();
            }
            return (T)retval;
        }

    }
}
